package com.yh.base.action;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.yh.app.common.util.SessionUtil;
import com.yh.base.common.Constant;
import com.yh.base.common.GlobalConfig;
import com.yh.base.service.BaseService;
import com.yh.base.util.ObjectUtil;
import com.yh.base.util.StringUtil;
import com.yh.base.vo.ResultInfoBean;
import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * 提供公用的方法
 * 
 * @author  严华
 * @version  [版本号, 2012-11-4]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class BaseAction extends ActionSupport {
    private final static Logger logger = Logger.getLogger(BaseAction.class);
    private static final long serialVersionUID = 1L;
    /** json返回值 */
    public static final String JSON_RESULT = "jsonResult";
    public static final String JSP_SUCCESS = "jspSuccess";

    @Autowired
    protected BaseService baseService;
    private String opertype;

    protected String sqlName;

    protected Integer pageSize = 10;
    protected Integer page = 1;
    protected String node;

    protected String CON_FILE_CONTENT = "CON_FILE_CONTENT";
    protected String CON_FILE_NAME = "CON_FILE_NAME";
    protected String CON_FILE_CONTENT_TYPE = "CON_FILE_CONTENT_TYPE";

    /**
     * 
     * 使用该方法取参数，页面参数不再需要condition. 如果同名参数到后台，返回的value为数组结构
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return Map<String, Object> Map(Key:Value)
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings({ "rawtypes", "unchecked", "static-access" })
    public Map getParameterMap() {
        HttpServletRequest request = ServletActionContext.getRequest();
        Map map = request.getParameterMap();
        Map resultParams = new HashMap();

        // 分页参数
        if (resultParams.get("page") == null && StringUtil.isValid(this.node)) {
            resultParams.put("root_id", this.node);
        }
        if (resultParams.get("page") == null) {
            resultParams.put("page", this.page);
        }
        if (resultParams.get("limit") == null) {
            resultParams.put("limit", this.pageSize);
        }
        resultParams.put("minSize", this.pageSize * (this.page - 1) + 1);
        resultParams.put("maxSize", this.pageSize * this.page);
        
        // 取默认Session参数
        com.yh.app.common.Constant appCon = new com.yh.app.common.Constant();
        
        // 员工登陆时个人信息Session常量
        resultParams.put(appCon.SESSION_USER_ID, SessionUtil.getSessionAttributeValue(appCon.SESSION_USER_ID, request));
        resultParams.put(appCon.SESSION_User_NAME, SessionUtil.getSessionAttributeValue(appCon.SESSION_User_NAME, request));
        resultParams.put(appCon.SESSION_LOGIN_CODE, SessionUtil.getSessionAttributeValue(appCon.SESSION_LOGIN_CODE, request));
        resultParams.put(appCon.SESSION_LAST_LOGIN_DATE, SessionUtil.getSessionAttributeValue(appCon.SESSION_LAST_LOGIN_DATE, request));
        // 员工登陆时角色信息Session常量
        resultParams.put(appCon.SESSION_ROLE_IDS, SessionUtil.getSessionAttributeValue(appCon.SESSION_ROLE_IDS, request));
        resultParams.put(appCon.SESSION_ROLE_LIST, SessionUtil.getSessionAttributeValue(appCon.SESSION_ROLE_LIST, request));
        // 员工登陆时菜单信息Session常量
        //resultParams.put(appCon.SESSION_MENU_INFO_LIST, SessionUtil.getSessionAttributeValue(appCon.SESSION_MENU_INFO_LIST, request));

        // 前台参数获取，会覆盖从session中取得的同名值
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            Object key = entry.getKey();
            Object val = entry.getValue();
            if (val != null && val instanceof Object[] && ((Object[]) val).length == 1) {
				// 我们需要的真实参数值
				Object realValue = ((Object[]) val)[0];
				if (StringUtil.isValid(realValue)) {
					// 数组格式，但只有一个元素的，返回字符串
					resultParams.put(key, realValue);
				}
            } else if (val != null) {
                // 其他格式的，直接返回(可能存在File[]格式)
                resultParams.put(key, val);
            }
        }

        return resultParams;
    }

    /**
     * 
     * 列表查询
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings("unchecked")
    public String findList() {
        logger.debug("findList:sqlName=" + this.sqlName);

        List<Map<String, String>> list = this.baseService.findList(this.sqlName, getParameterMap());
        logger.debug("findList:List.size=" + list.size());

        putValueStack(list);
        return JSON_RESULT;
    }

    /**
     * 
     * 通用分页查询
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    public String findListPaged() {
        /*List<Map<String, String>> dataList = this.baseService.findPageList(sqlName, getParameterMap());
        Integer total = this.baseService.findListTotal(sqlName, getParameterMap());

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("Total", total);
        resultMap.put("Rows", dataList);

        putValueStack(resultMap);*/
        return JSON_RESULT;
    }

    /**
     * 
     * 通用新增方法
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings("unchecked")
    public String comAdd() {
        Integer cnt = this.baseService.comAdd(sqlName, getParameterMap());

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("cnt", cnt);
        resultMap.put("msg", "数据新增成功");

        putValueStack(resultMap);
        return JSON_RESULT;
    }

    /**
     * 
     * 通用修改方法
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings("unchecked")
    public String comMod() {
        Integer cnt = this.baseService.comMod(sqlName, getParameterMap());

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("cnt", cnt);
        resultMap.put("msg", "数据修改成功");

        putValueStack(resultMap);
        return JSON_RESULT;
    }

    /**
     * 
     * 通用删除方法
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings("unchecked")
    public String comDel() {
        Integer cnt = this.baseService.comDel(sqlName, getParameterMap());

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("cnt", cnt);
        resultMap.put("msg", "数据删除成功");

        putValueStack(resultMap);
        return JSON_RESULT;
    }

    /**
     * 
     * 通用下载，需要参数 附件ID
     *
     * @author  严华
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public String downLoadAttach() {
        ResultInfoBean ret = new ResultInfoBean("0");
        Map param = getParameterMap();
        List<Map<String, String>> fileList = baseService.findList("common.commAttachFileCount", getParameterMap());
        if (fileList != null && fileList.size() > 0) {
            try {
                HttpServletResponse response = ServletActionContext.getResponse();
                InputStream inputStream = null;
                String filePath = fileList.get(0).get("FILE_DESC");
                if (filePath == null || "".equals(filePath)) {
                    // 数据库存储格式
                    inputStream = new ByteArrayInputStream("".getBytes());

                    WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext
                            .getServletContext());
                    JdbcTemplate jdbcTemplate = (JdbcTemplate) wac.getBean(ObjectUtil.toString(GlobalConfig.newInstance().get(
                            "ibatisTemplate_name")));

                    String sql = "select file_content from com_attach_file t where file_id =" + param.get("attachId");
                    final InputStream[] fileInputStream = { null };
                    jdbcTemplate.execute(sql, new CallableStatementCallback() {
                        public Object doInCallableStatement(CallableStatement stmt) throws SQLException, DataAccessException {
                            ResultSet rs = stmt.executeQuery();
                            while (rs.next()) {
                                fileInputStream[0] = rs.getBinaryStream("file_content");// 读取数据库Binary流
                            }
                            return null;
                        }
                    });
                    inputStream = fileInputStream[0];
                } else {
                    // 判断文件是否存在
                    File attachFile = new File(filePath);
                    if (attachFile.exists()) {
                        // 文件存储格式
                        inputStream = new FileInputStream(filePath);
                    } else {
                        logger.error("请求的文件不存在！附件存储路径：[" + filePath + "]");
                        ret.setMsg("请求的文件不存在！附件存储路径：[" + filePath + "]");
                    }
                }
                // 写文件流
                byte[] buf = new byte[1024];
                int len = 0;
                response.reset();
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/x-msdownload");
                response.setHeader("Content-Disposition",
                        "attachment; filename=" + java.net.URLEncoder.encode(fileList.get(0).get("FILE_NAME"), "UTF-8"));
                OutputStream out = response.getOutputStream();
                while ((len = inputStream.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                inputStream.close();
                out.close();
                return null;
            } catch (Exception e) {
                logger.error("附件下载过程中出现错误！附件ID：[" + param.get("attachId") + "]");
                ret.setMsg("附件下载过程中出现错误！附件ID：[" + param.get("attachId") + "]");
            }
        } else {
            logger.error("请求的文件不存在！附件ID：[" + param.get("attachId") + "]");
            ret.setMsg("请求的文件不存在！附件ID：[" + param.get("attachId") + "]");
        }
        putValueStack(ret);
        return JSON_RESULT;
    }

    // 上传文件时专用
    private boolean isNonEmpty(Object[] objArray) {
        boolean result = false;
        for (int index = 0; index < objArray.length && !result; index++) {
            if (objArray[index] != null) {
                result = true;
            }
        }
        return result;
    }

    /**
     * 读取上传文件的属性信息，返回的List中是Map，暂时没写专门针对上传解析功能<br/>
     * 
     * <pre>
     * Map中存在三个Key1    CON_FILE_CONTENT   ： 文件内容，File格式
     *              Key2    CON_FILE_NAME      : 文件名，String格式
     *              Key3 CON_FILE_CONTENT_TYPE : 文件类型，String格式
     * </pre>
     * 
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Deprecated
    protected List<Map> getUploadFileInfo() {
        List<Map> reMapList = new ArrayList<Map>();
        // 检查是否是文件上传格式
        HttpServletRequest request = ServletActionContext.getRequest();
        if (!(request instanceof MultiPartRequestWrapper)) {
            logger.error("非文件上传格式的Form，请设置Form参数：method =\"POST\" enctype =\"multipart/form-data\"");
            return null;
        }
        MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;

        Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
        while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
            // get the value of this input tag
            String inputName = (String) fileParameterNames.nextElement();

            // get the content type
            String[] contentType = multiWrapper.getContentTypes(inputName);

            if (isNonEmpty(contentType)) {
                // get the name of the file from the input tag
                String[] fileName = multiWrapper.getFileNames(inputName);

                if (isNonEmpty(fileName)) {
                    // get a File object for the uploaded File
                    File[] files = multiWrapper.getFiles(inputName);
                    if (files != null && files.length > 0) {
                        // List<File> acceptedFiles = new ArrayList<File>(files.length);
                        // List<String> acceptedContentTypes = new ArrayList<String>(files.length);
                        // List<String> acceptedFileNames = new ArrayList<String>(files.length);
                        // String contentTypeName = inputName + "ContentType";
                        // String fileNameName = inputName + "FileName";

                        for (int index = 0; index < files.length; index++) {
                            Map map = new HashMap();
                            map.put(CON_FILE_CONTENT, files[index]);
                            map.put(CON_FILE_NAME, fileName[index]);
                            map.put(CON_FILE_CONTENT_TYPE, contentType[index]);
                            reMapList.add(map);
                        }
                    }
                }
            }
        }
        return reMapList;
    }

    /**
     * 
     * 返回JSON的时候，直接放对象到ValueStack中
     *
     * @author  严华
     * @param obj [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    public void putValueStack(Object obj) {
        ServletActionContext.getContext().getValueStack().set(Constant.CON_JSON_RESULT_VALUE_KEY, obj);
    }

    /**
     * 
     * 返回页面的时候，设置页面ID
     *
     * @author  严华
     * @param pageName [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    public void setForwardPageName(String pageName) {
        ServletActionContext.getContext().getValueStack().set(Constant.CON_PAGE_RESULT_VALUE_KEY, pageName);
    }

    /**
     * 
     * 修改页面单条数据Put值
     *
     * @author  严华
     * @param map [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    @SuppressWarnings("rawtypes")
    public void putValueStackOne(Map map) {
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            ServletActionContext.getContext().getValueStack()
                    .set(StringUtil.lowerCase(ObjectUtil.toString(entry.getKey())), entry.getValue());
        }
    }

    /**
     * 
     * 获取对应SQL的全路径
     *
     * @author  严华
     * @param cls 当前调用类
     * @param sqlId "model.xml文件名" + "." + "sqlId"
     * @return cls.pakege+ model.modlename.sqlId
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     */
    protected String getFullSqlId(Object cls, String sqlId) {
        String retSqlId = StringUtil.substringBeforeLast(cls.getClass().getPackage().getName(), ".");
        retSqlId += ".model." + sqlId;
        return retSqlId;
    }

    public String getSqlName() {
        return sqlName;
    }

    public void setSqlName(String sqlName) {
        this.sqlName = sqlName;
    }

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public String getNode() {
        return node;
    }

    public void setNode(String node) {
        this.node = node;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public BaseService getBaseService() {
        return baseService;
    }

    public void setBaseService(BaseService baseService) {
        this.baseService = baseService;
    }

    public String getOpertype() {
        return opertype;
    }

    public void setOpertype(String opertype) {
        this.opertype = opertype;
    }

}